package com.dpiinc.TechPage.pen.activity

import android.os.Bundle
import android.util.DisplayMetrics
import android.util.Log
import android.view.Menu
import android.view.MenuItem
import android.view.WindowManager
import android.widget.SeekBar
import com.dpiinc.TechPage.BaseActivity
import com.dpiinc.TechPage.R
import com.dpiinc.TechPage.activity.EditNoteActivity
import com.dpiinc.TechPage.user.utils.PermissionUtils
import com.dpiinc.TechPage.user.utils.ToastUtils
import com.dpiinc.TechPage.utils.DateUtils
import com.dpiinc.TechPage.video.ShareVideoHelper
import com.beiji.lib.pen.PenLog
import com.beiji.lib.pen.cache.PenCacheManager
import com.beiji.lib.pen.constants.PaletteColor
import com.beiji.lib.pen.model.DotUnit
import com.beiji.lib.pen.model.PenStroke
import com.dpiinc.TechPage.widget.LoadingView
import com.tqltech.tqlpencomm.bean.Dot
import com.yanzhenjie.permission.Action
import kotlinx.android.synthetic.main.activity_replay.*
import kotlinx.coroutines.*
import java.util.*

/**
 * 笔迹回放
 */
class ReplayActivity : BaseActivity() {

    companion object {
        const val TAG = "Replay"
        const val ARG_NOTE_KEY = "arg_note_key"
        const val REPLAY_DRAW_DELAY_PERIOD_1X = 30L//绘制每一个点的延迟时间，单位是ms
        const val REPLAY_DRAW_DELAY_PERIOD_2X = 15L
        const val REPLAY_DRAW_DELAY_PERIOD_4X = 8L
        const val TIME_FORMAT_STR_SHORT = "mm:ss"
        const val TIME_FORMAT_STR_LONG = "HH:mm:ss"
    }

    private var curDelayPeriod = REPLAY_DRAW_DELAY_PERIOD_1X
    private var totalTime: Long = 0
    private var totalTimeString: String? = null
    private var totalDotCount = 0
    private var timeFormatStr = TIME_FORMAT_STR_SHORT
    private var strokeList = ArrayList<PenStroke>()
    private var curDotIndex = 1
    private var curProgress = 0
    private var isPlaying = false
    private var drawJob: Job? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_replay)
        setSupportActionBar(toolbar)
        supportActionBar?.setDisplayShowTitleEnabled(false)
        val noteId = intent.getStringExtra(ARG_NOTE_KEY)
        if (noteId.isNullOrEmpty()) {
            finish()
            return
        }
        toolbar.setNavigationOnClickListener { finish() }
        PenCacheManager.instance.loadCache(noteId, null)
        PenCacheManager.instance.getCurrentCache()?.readStrokesFromFile {
            strokeList = it
            if (strokeList.isEmpty()) {
                ToastUtils.showCenterTip(this,getString(R.string.toast_replay_empty_stroke))
                LoadingView.dismissLoadingView()
                finish()
                return@readStrokesFromFile
            }
            calculateTotalTime(it)
            setProgressText(0)
        }
        progress_bar.setOnSeekBarChangeListener(onSeekBarChangeListener)
        tv_speed.setOnClickListener {
            when (curDelayPeriod) {
                REPLAY_DRAW_DELAY_PERIOD_1X -> {
                    curDelayPeriod = REPLAY_DRAW_DELAY_PERIOD_2X
                    tv_speed.setText(R.string.replay_speed_2X_text)
                }
                REPLAY_DRAW_DELAY_PERIOD_2X -> {
                    curDelayPeriod = REPLAY_DRAW_DELAY_PERIOD_4X
                    tv_speed.setText(R.string.replay_speed_4X_text)
                }
                REPLAY_DRAW_DELAY_PERIOD_4X -> {
                    curDelayPeriod = REPLAY_DRAW_DELAY_PERIOD_1X
                    tv_speed.setText(R.string.replay_speed_1X_text)
                }
                else -> {
                }
            }
        }
        btn_start_play.setOnClickListener {
            if (isPlaying) {
                drawJob?.cancel(null)
                isPlaying = false
            } else {
                drawStrokesFromProgressAndPlay(strokeList, curProgress)
            }
            updatePlayButtonState()
        }
    }

    private fun calculateTotalTime(strokeList: ArrayList<PenStroke>) {
        totalDotCount = 0
        strokeList.forEach { stroke ->
            stroke.list.forEach { _ ->
                totalDotCount++
            }
        }
        PenLog.e(TAG, "totalCount ->$totalDotCount")
        totalTime = REPLAY_DRAW_DELAY_PERIOD_1X * totalDotCount
        timeFormatStr = if (totalTime > 3600 * 1000) {//超过1小时
            TIME_FORMAT_STR_LONG
        } else {
            TIME_FORMAT_STR_SHORT
        }
        PenLog.e(TAG, "totalTime ->$totalTime")
        totalTimeString = DateUtils.getDurationString(totalTime, timeFormatStr)
        PenLog.e(TAG, "totalCountStr ->$totalTimeString")
    }

    private fun calculateProgress(curDotIndex: Int): Int {
        PenLog.i(TAG, "$curDotIndex ->$totalDotCount")
        return (curDotIndex.toFloat() / totalDotCount * 100).toInt()
    }

    private fun getDotIndexByProgress(progress: Int): Int {
        return (totalDotCount * progress / 100f).toInt()
    }

    private fun updateProgress(curDotIndex: Int, isPlayMode: Boolean) {
        val progress = calculateProgress(curDotIndex)
        curProgress = progress
        if (isPlayMode) {
            progress_bar.progress = progress
        }
    }

    private fun setProgressText(progress: Int) {
        val curTime = (progress / 100f * totalTime).toLong()
        val curTimeStr = DateUtils.getDurationString(curTime, timeFormatStr)
        PenLog.i(TAG, "progress ->$progress")
        tv_progress_play.text=curTimeStr
        tv_progress_end.text=totalTimeString
    }

    private fun updatePlayButtonState() {
        if (isPlaying) {
            btn_start_play.setImageResource(R.mipmap.ic_replay_pause)
        } else {
            btn_start_play.setImageResource(R.mipmap.ic_replay_start)
        }
    }


    private val onSeekBarChangeListener = object : SeekBar.OnSeekBarChangeListener {
        override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
            curProgress = progress
            setProgressText(progress)
            if (progress >= 100) {
                isPlaying = false
            }
            updatePlayButtonState()
        }

        override fun onStartTrackingTouch(seekBar: SeekBar?) {
            val result = drawJob?.cancel(null) ?: false
            PenLog.e(TAG, "cancel result -> $result")
        }

        override fun onStopTrackingTouch(seekBar: SeekBar?) {
            val progress = seekBar?.progress ?: curProgress
            val endDotIndex = getDotIndexByProgress(progress)
            drawStrokesUntilDotIndex(strokeList, curDotIndex, endDotIndex)
        }
    }

    private fun drawStrokesFromProgressAndPlay(strokeList: ArrayList<PenStroke>, startProgress: Int) {
        isPlaying = true
        drawJob?.cancel(null)
        runBlocking {
            delay(100)
        }
        drawStrokesUntilProgress(strokeList, startProgress, 100, true)
    }


    @Synchronized
    private fun drawStrokesUntilProgress(strokeList: ArrayList<PenStroke>, startProgress: Int, endProgress: Int, playMode: Boolean = false) {
        val startDotIndex = getDotIndexByProgress(startProgress)
        val endDotIndex = getDotIndexByProgress(endProgress)
        drawStrokesUntilDotIndex(strokeList, startDotIndex, endDotIndex, playMode)
    }

    @Synchronized
    private fun drawStrokesUntilDotIndex(strokeList: ArrayList<PenStroke>, startDotIndex: Int, endDotIndex: Int, playMode: Boolean = false) {
        var isPlayMode = playMode
        var startIndex = startDotIndex
        if (startIndex >= endDotIndex) {
            startIndex = 0
            stroke_view.clearAllStroke()
        }
        val start = System.currentTimeMillis()
        drawJob = launch(CommonPool) {
            curDotIndex = 1
            strokeList.forEach { stroke ->
                if (drawJob != null && !drawJob!!.isActive) {
                    return@launch
                }
                for (i in stroke.list.indices) {
                    if (drawJob != null && !drawJob!!.isActive) {
                        return@launch
                    }
                    if (curDotIndex >= endDotIndex) {
                        if (isPlaying) {
                            isPlayMode = true
                        } else {
                            return@launch
                        }
                    }
                    if (curDotIndex > startIndex) {
                        val penPoint = stroke.list[i]
                        val dot = DotUnit().apply {
                            pageId = stroke.page
                            bookId = stroke.bookId
                            actionType = stroke.action
                            timestamp = stroke.time
                            x = penPoint.x
                            y = penPoint.y
                            force = penPoint.f
                        }
                        dot.type = when (i) {
                            0 -> Dot.DotType.PEN_DOWN
                            stroke.list.indices.last -> Dot.DotType.PEN_UP
                            else -> Dot.DotType.PEN_MOVE
                        }
                        if (stroke.action == PenStroke.ACTION_STROKE) {
                            stroke_view.setStrokeColor(PaletteColor.fromId(stroke.color))
                        }else if (stroke.action == PenStroke.ACTION_MARK) {
                            stroke_view.setMarkColor(PaletteColor.fromId(stroke.color))
                        }
                        //TODO Yang
//                        stroke_view.drawDot(dot, true)
                        stroke_view.drawDot(dot)
                        updateProgress(curDotIndex, isPlayMode)
                        if (isPlayMode) {
                            delay(curDelayPeriod)
                        }
                    }
                    curDotIndex++
                }
            }
            Log.e("costTime", "${System.currentTimeMillis() - start}")
        }
    }

    override fun onCreateOptionsMenu(menu: Menu?): Boolean {
        menuInflater.inflate(R.menu.menu_replay_share, menu)
        return super.onCreateOptionsMenu(menu)
    }

    override fun onOptionsItemSelected(item: MenuItem): Boolean {
        when (item.itemId) {
            R.id.toolbar_share -> {
                if (strokeList.size > 0) {
                    if (isPlaying) {
                        drawJob?.cancel(null)
                        isPlaying = false
                    }
                    updatePlayButtonState()
                    checkPermissionShowDialog(strokeList)
                } else {
                    ToastUtils.showCenterTip(this,getString(R.string.data_loading))
                }
            }
        }
        return super.onOptionsItemSelected(item)
    }

    private fun checkPermissionShowDialog(strokeList: ArrayList<PenStroke>) {
        var isTen = true;
        val time = totalTimeString!!.split(":".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
        if (time[0].toInt() == 0 && time[1].toInt() < 10) {
            isTen = false
        }
        val wm = this.getSystemService(WINDOW_SERVICE) as WindowManager
        val dm = DisplayMetrics()
        wm.defaultDisplay.getMetrics(dm)
        val width = dm.widthPixels         // 屏幕宽度（像素）
        val granted = Action<List<String>> {
            ShareVideoHelper.showShareDialog(this@ReplayActivity, strokeList, isTen,width)
        }
        val denied = Action<List<String>> {
            ToastUtils.showTopTip(this@ReplayActivity, getString(R.string.no_authority_share))
            Log.d(EditNoteActivity.TAG, "onAction denied")
        }
        if (PermissionUtils.checkWRITE_EXTERNAL_STORAGE(this@ReplayActivity, granted, denied)) {
            ShareVideoHelper.showShareDialog(this@ReplayActivity, strokeList, isTen,width)
        }

    }

    override fun onDestroy() {
        isPlaying = false
        drawJob?.cancel(null)
        super.onDestroy()
    }

}
